package com.youlu.campus.admin.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.admin.auth.common.DeviceType;
import com.youlu.campus.admin.auth.entity.exception.AuthErrorCode;
import com.youlu.campus.admin.auth.service.AuthTokenService;
import com.youlu.campus.admin.auth.service.UserService;
import com.youlu.campus.admin.auth.shiro.exception.AuthException;
import com.youlu.campus.admin.auth.shiro.token.AuthToken;
import com.youlu.campus.admin.common.LoggerService;
import com.youlu.campus.base.base.Constants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * Created by zhuhuaiqi
 */
@Service("authTokenService")
public class AuthTokenServiceImpl extends LoggerService implements AuthTokenService {

    @Autowired
    UserService userService;
    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public void withAuthTokenCache(AuthToken authToken) {

        try {
            logger.info(":>>> 开始设置缓存缓存 withAuthTokenCache:{}", JSON.toJSONString(authToken));
            String userId = authToken.getUid();
            String key = getAuthTokenRedisKey(userId);
            String json = JSON.toJSONString(authToken);
            logger.debug("withAuthToken to redis key:{}, json:{}", key, json);
            redisTemplate.opsForValue().set(key, json);
            //jc.expire(getAuthTokenRedisKey(userId), Constants.REDIS_EXPIRE_TIME_L);
            int expired = getAuthExpired(authToken);
            logger.debug(":>>> 设置Token 缓存过期时间:{} 分钟 to redis key:{}, json:{}", key, json, expired);
            redisTemplate.expire(key, expired, TimeUnit.MINUTES);
            logger.debug(":>>> 设置Token 缓存过期时间:{} 分钟 to redis key:{}, json:{}", key, json, expired);
        } catch (Exception e) {
            logger.error(":>>> withAuthTokenCache 错误:{}", e);

        } finally {
            // TODO: 错误处理
        }
    }

    @Override
    public Boolean checkAuthTokenCache(String userId, String jti, Boolean updateTtl) {
        boolean result = false;
        try {
            String key = getAuthTokenRedisKey(userId);
            logger.debug("getAuthTokenCache to redis key:{}", key);
            String json = (String) redisTemplate.opsForValue().get(key);
            logger.debug(":>>> getAuthTokenCache to redis key:{},token:{}", key, json);
            //凭据已过期
            if (StringUtils.isEmpty(json)) {
                logger.error(":>>> 用户:{} jwt token已经失效");
                throw new AuthException(AuthErrorCode.EXPIRED_AUTH_TOKEN);
            }
            AuthToken authToken = null;

            authToken = JSON.parseObject(json, AuthToken.class);
            long now = System.currentTimeMillis();
//            logger.info("checkAuthTokenCache userId:{}, jti:{}, getnowTime:{}, authToken json:{}",
//                    userId, jti, now, JSON.toJSONString(authToken));
            if (authToken == null) {
                logger.debug("checkAuthTokenCache authToken null");
                throw new AuthException(AuthErrorCode.USER_NOT_LOGIN);
            }
            //不相等，强制下线
            //TODO:
//            if (!StringUtils.equalsIgnoreCase(jti, authToken.getJti())) {
//                throw new AuthException(AuthErrorCode.DOWNLINE_AUTH_TOKEN);
//            }
//            long expiresIn = now - authToken.getLastAccessTime();
            //logger.debug("checkAuthTokenCache calc now:{}, last:{}, result:{},tokenex:{}", now,
            // authToken.getLastAccessTime(), expiresIn, authToken.getExpiresIn());
            // 访问凭据失效
//            if (authToken.getExpiresIn() < expiresIn) {
//                logger.error(":>>> 用户Token过期");
//                throw new AuthException(AuthErrorCode.EXPIRED_AUTH_TOKEN);
//            }
            authToken.setLastAccessTime(now);
            logger.debug("checkAuthTokenCache userId:{}, updateTtl:{}, nowTime:{}", userId, updateTtl, now);
            if (updateTtl) {
                int expired = getAuthExpired(authToken);
                redisTemplate.opsForValue().set(key, JSON.toJSONString(authToken), expired, TimeUnit.SECONDS);
            }
            int expired = getAuthExpired(authToken);
            redisTemplate.opsForValue().set(key, JSON.toJSONString(authToken), expired, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            logger.error(":>>> 检查token 错误:{}", e);
            return false;
        }

        return result;
    }

    @Override
    public void expireAuthTokenCache(String userId, int seconds) {
        try {
            String key = getAuthTokenRedisKey(userId);
            logger.debug("延长: {} 的时间为 {} 秒", key, seconds);
            redisTemplate.expire(key, seconds, TimeUnit.MINUTES);
        } catch (Exception e) {
            logger.error(":>>> 过期时间错误:{}", e);
            return;
        }
    }

    /**
     * 获取过期时间
     *
     * @param authToken
     * @return
     */
    private int getAuthExpired(AuthToken authToken) {
        int expired = authToken.getExpiresIn() * 100;
        //int expired = 10;
        logger.info(":>>> token过期的时间 :{}", expired);
        return expired;
    }

    @Override
    public AuthToken getAuthTokenCache(String userId) {
        AuthToken authToken = null;
        String key = getAuthTokenRedisKey(userId);
        logger.debug(":>>> getAuthTokenCache to redis key:{}", key);
        try {
            String value = (String) redisTemplate.opsForValue().get(key);
            if (StringUtils.isBlank(value)) {
                logger.error(":>>> key:{} 的authToken不存在", key);
                return null;
            }
            authToken = JSON.parseObject(value, AuthToken.class);

        } catch (Exception e) {
            logger.error(":>>> 获取:{},Token失败", key);
            return null;
        }
        return authToken;
    }

    @Override
    public void clearAuthTokenCache(String userId) {
        try {
            String key = getAuthTokenRedisKey(userId);
            logger.debug("AuthTokenServiceImpl.clearAuthTokenCache to redis key:{}", key);
            redisTemplate.delete(key);
        } catch (Exception e) {
            logger.error(":>>> 删除token失败:{}", userId);
            return;
        }

    }

    private String getAuthTokenRedisKey(String userId) {
        return String.format(Constants.REDIS_AUTH_USER_TOKEN, userId);
    }

    private String getAuthTokenAccessTtlRedisKey(Long userId, DeviceType deviceType) {
        return String.format(Constants.REDIS_AUTH_TOKEN_ACCESS_TTL, userId, deviceType);
    }

    private String getUserPushDeviceTypeKey(String userId, DeviceType deviceType) {
        logger.debug("AuthTokenServiceImpl.getUserPushDeviceTypeKey userId:{}, deviceType:{}", userId,
                deviceType);
        if (DeviceType.IOS == deviceType || DeviceType.ANDROID == deviceType) {
            return String.format(Constants.REDIS_APP_PUSH_USER_ID, userId);
        }
        return null;

    }

}
